
package com.rt.schedulenew.service.impl;

import com.rt.schedulebase.dto.*;
import com.rt.schedulebase.entity.DictDept;
import com.rt.schedulebase.entity.DictScheduleApmRegular;
import com.rt.schedulenew.api.ICommonService;
import com.rt.schedulenew.api.IDictDeptService;
import com.rt.schedulenew.utils.base.CommonUtil;
import com.rt.schedulenew.utils.base.ConstantsUtil;
import com.rt.schedulenew.utils.util.DateUtil;
import com.rt.schedulenew.utils.util.EhCacheUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 预约规则引擎服务
 */
@Service
public class RuleEngineServiceImpl {
    private static final Logger log = LoggerFactory.getLogger(RuleEngineServiceImpl.class);
    @Autowired
    private CacheServiceImpl cacheServiceImpl;
    @Autowired
    private ICommonService commonServiceImpl;
    @Autowired
    private DictScheduleApmRegularServiceImpl dictScheduleApmRegularServiceImpl;
    @Autowired
    private IDictDeptService dictDeptService;

    /**
     * 验证申请单和预约规则是否匹配
     *
     * @param rule
     * @param examApply
     * @param date
     * @return true 匹配 false 不匹配
     */
    public boolean ruleJudge(RuleDto rule, ExamApplyDto examApply, String date) {
        // isStop true 不能用 false 可以用
        boolean isStop = false;
        // 是否排斥 1 排斥 0 允许
        /**
         * 是否排斥 true 排斥 false 允许
         */
        boolean isExclude = "1".equals(rule.getExcludeFlag());
        List<String> ruleItems = (rule.getExamItem() != null) ? rule.getExamItem().getValue() : null;
        List<DictExamItemDto> ruleDictItems = rule.getDictExamItemList();
        // 排斥且检查项目包含在排斥项目里面
        if (isExclude && CollectionUtils.isNotEmpty(ruleItems)) {
            boolean isItem = false;
            for (ExamApplyItemDto e : examApply.getItems()) {
                if (ruleItems.contains(e.getItemCode())) {
                    isItem = true;
                    break;
                }
            }
            // 排斥 且 没有包含在排斥里面的检查类别 直接通过
            if (!isItem) {
                return isStop;
            }
        }

        // 获取规则里面的   项目属性
        StringBuilder onlyDoItemBuf = new StringBuilder();
        StringBuilder noDoItemBuf = new StringBuilder();
        String calm = rule.getCalm();
        if ("1".equals(calm)) {
            onlyDoItemBuf.append(",1");
        } else if ("0".equals(calm)) {
            noDoItemBuf.append(",1");
        }
        String enhance = rule.getEnhance();
        if ("1".equals(enhance)) {
            onlyDoItemBuf.append(",2");
        } else if ("0".equals(enhance)) {
            noDoItemBuf.append(",2");
        }
        String emptyStomach = rule.getEmptyStomach();
        if ("1".equals(emptyStomach)) {
            onlyDoItemBuf.append(",3");
        } else if ("0".equals(emptyStomach)) {
            noDoItemBuf.append(",3");
        }
        String bernao = rule.getBernao();
        if ("1".equals(bernao)) {
            onlyDoItemBuf.append(",4");
        } else if ("0".equals(bernao)) {
            noDoItemBuf.append(",4");
        }
        String puncture = rule.getPuncture();
        if ("1".equals(puncture)) {
            onlyDoItemBuf.append(",5");
        } else if ("0".equals(puncture)) {
            noDoItemBuf.append(",5");
        }
        boolean isConfigure = false;
        int firstScheduleOrder = 0;

        // 是否有检测项目标记为特殊
        boolean isSpecial = false;
        // 标记为单个项目特殊
        boolean isSingleSpecial = false;
        // 标记为多项目特殊
        boolean isMultiSpecial = false;
        if (CollectionUtils.isNotEmpty(ruleDictItems)) {
            List<String> applyItemCodes = examApply.getItems().stream()
                    .map(x -> x.getItemCode()).collect(Collectors.toList());

            List<DictExamItemDto> itemDtos = ruleDictItems.stream()
                    .filter(x -> applyItemCodes.contains(x.getItemCode()) && (Objects.nonNull(x.getIsSpecial()) && x.getIsSpecial()))
                    .collect(Collectors.toList());
            isSpecial = CollectionUtils.isNotEmpty(itemDtos);

            List<DictExamItemDto> signItemDtos = ruleDictItems.stream()
                    .filter(x -> applyItemCodes.contains(x.getItemCode()) && (Objects.nonNull(x.getIsSingleSpecial()) && x.getIsSingleSpecial()))
                    .collect(Collectors.toList());
            isSingleSpecial = CollectionUtils.isNotEmpty(signItemDtos);

            List<DictExamItemDto> multiItemDtos = ruleDictItems.stream()
                    .filter(x -> applyItemCodes.contains(x.getItemCode()) && (Objects.nonNull(x.getIsMultiSpecial()) && x.getIsMultiSpecial()))
                    .collect(Collectors.toList());
            isMultiSpecial = CollectionUtils.isNotEmpty(multiItemDtos);
        }

        for (ExamApplyItemDto applyItemDto : examApply.getItems()) {
            // 允许 规则
            if (!isExclude) {
                // 项目优先级-普通、急诊、优先
                boolean isItemOrder = applyItemDto.getScheduleOrderGroup() == null;
                String scheduleOrder = (applyItemDto.getScheduleOrder() == null) ? "" : String.valueOf(applyItemDto.getScheduleOrder());
                if (!isItemOrder) {
                    scheduleOrder = ((applyItemDto.getScheduleOrderGroup() == null) ? "" : String.valueOf(applyItemDto.getScheduleOrderGroup()));
                }
                if (StringUtils.isNotBlank(scheduleOrder)) {
                    if (firstScheduleOrder == 0) {
                        firstScheduleOrder = Integer.parseInt(scheduleOrder);
                    } else if (firstScheduleOrder > Integer.parseInt(scheduleOrder)) {
                        continue;
                    }
                }

                // 标记为单个特殊 且预约的申请单里检查项目有多个 就直接停止
                if (isSingleSpecial && examApply.getItems().size() > 1) {
                    isStop = true;
                    break;
                }
                // 标记为多项目特殊 且预约的申请单里检查项目里只有一个 就直接停止
                if (isMultiSpecial && examApply.getItems().size() <= 1) {
                    isStop = true;
                    break;
                }

                // 项目编码没有在允许的项目里面就不能用
                if (CollectionUtils.isEmpty(ruleItems)
                        || (CollectionUtils.isNotEmpty(ruleItems) && !ruleItems.contains(applyItemDto.getItemCode()))) {
                    if (!isSpecial) {
                        isStop = true;
                        break;
                    }
                }
            }
            List<String> itemFlags = CommonUtil.examItemFlag(applyItemDto.getFlags());
            String onlyDoItem = StringUtils.isNotBlank(onlyDoItemBuf.toString()) ? onlyDoItemBuf.substring(1) : "";
            String noDoItem = StringUtils.isNotBlank(noDoItemBuf.toString()) ? noDoItemBuf.substring(1) : "";
            String[] onlyDoItemArr = onlyDoItem.split(",");
            String[] noDoItemArr = noDoItem.split(",");
            // 排斥
            if (isExclude) {
                // 排斥-只做
                if (CollectionUtils.isNotEmpty(itemFlags) && StringUtils.isNotBlank(onlyDoItem)) {
                    for (String flags : onlyDoItemArr) {
                        if (itemFlags.contains(flags)) {
                            isStop = true;
                            break;
                        }
                    }
                    isConfigure = true;
                }
                if (isStop || StringUtils.isBlank(noDoItem)) {
                    continue;
                }
                for (String flags : noDoItemArr) {
                    if (!itemFlags.contains(flags)) {
                        isStop = true;
                        break;
                    }
                }
                isConfigure = true;
            } else {
                // 允许 - 不做
                if (CollectionUtils.isNotEmpty(itemFlags) && StringUtils.isNotBlank(noDoItem)) {
                    for (String flags : noDoItemArr) {
                        if (itemFlags.contains(flags)) {
                            isStop = true;
                            break;
                        }
                    }
                }
                if (isStop || !StringUtils.isNotBlank(onlyDoItem)) {
                    continue;
                }
                for (String flags : onlyDoItemArr) {
                    if (!itemFlags.contains(flags)) {
                        isStop = true;
                        break;
                    }
                }
            }
        }
        // 如果有匹配 就返回匹配
        if (isStop) {
            return isStop;
        }

        // 申请医生
        List<String> reqPhysician = null;
        String reqPhysicianGrant = null;
        if (rule.getReqPhysician() != null) {
            reqPhysician = rule.getReqPhysician().getValue();
            reqPhysicianGrant = rule.getReqPhysician().getGrant();
        }
        // 优先级
        List<String> priorityOrder = null;
        String priorityOrderGrant = null;
        if (rule.getPriorityOrder() != null) {
            priorityOrder = rule.getPriorityOrder().getValue();
            priorityOrderGrant = rule.getPriorityOrder().getGrant();
        }
        // 终端类型
        List<String> terminalTypes = null;
        String terminalTypeGrant = null;
        if (rule.getTerminalType() != null) {
            terminalTypes = rule.getTerminalType().getValue();
            terminalTypeGrant = rule.getTerminalType().getGrant();
        }
        // 申请病区
        List<String> ward = null;
        String wardGrant = null;
        if (rule.getWard() != null) {
            ward = rule.getWard().getValue();
            wardGrant = rule.getWard().getGrant();
        }
        // 申请科室
        List<String> dept = null;
        String deptGrant = null;
        if (rule.getDept() != null) {
            dept = rule.getDept().getValue();
            deptGrant = rule.getDept().getGrant();
        }
        // 护理单元
        List<String> nurseUnitList = null;
        String nurseUnitGrant = null;
        String nurseUnit = examApply.getNurseUnit();
        if (rule.getNurseUnit() != null) {
            nurseUnitList = rule.getNurseUnit().getValue();
            nurseUnitGrant = rule.getNurseUnit().getGrant();
            if (StringUtils.isNotBlank(nurseUnit)) {
                // 根据申请单护理单元 名称获取 科室列表
                DictDeptDto dto = new DictDeptDto();
                dto.setDeptName(examApply.getNurseUnit());
                List<DictDept> list = dictDeptService.getList(dto);
                if (CollectionUtils.isNotEmpty(list)) {
                    nurseUnit = list.get(0).getDeptCode();
                }
            }
        }
        // 病人来源
        List<String> patientSource = null;
        String patientSourceGrant = null;
        if (rule.getPatientSource() != null) {
            patientSource = rule.getPatientSource().getValue();
            patientSourceGrant = rule.getPatientSource().getGrant();
            // 住院来源名称重新赋值
            if (patientSource.contains("住院")) {
                String patientSourceIn = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.PATIENT_SOURCE_IN.getKey());
                if (StringUtils.isNotBlank(patientSourceIn)) {
                    patientSource.add(patientSourceIn);
                }
            }
        }
        // 病人性别
        List<String> sex = null;
        String sexGrant = null;
        if (rule.getSex() != null) {
            sex = rule.getSex().getValue();
            sexGrant = rule.getSex().getGrant();
        }
        // 运送工具
        List<String> transTool = null;
        String transToolGrant = null;
        if (rule.getTransTool() != null) {
            transTool = rule.getTransTool().getValue();
            transToolGrant = rule.getTransTool().getGrant();
        }
        // 诊断关键词
        List<String> diagnosKeyword = null;
        String diagnosKeywordGrant = null;
        if (rule.getDiagnosticKeyword() != null) {
            diagnosKeyword = rule.getDiagnosticKeyword().getValue();
            diagnosKeywordGrant = rule.getDiagnosticKeyword().getGrant();
        }
        // 年龄范围
        List<RuleDto.DayScope> dayScope = null;
        String dayScopeGrant = null;
        if (rule.getAge() != null) {
            dayScope = rule.getAge().getDayScope();
            dayScopeGrant = rule.getAge().getGrant();
        }
        boolean isAgeScope = true;
        if (CollectionUtils.isNotEmpty(dayScope)) {
            for (RuleDto.DayScope day : dayScope) {
                int min = day.getMin();
                int max = day.getMax();
                if (StringUtils.isNotBlank(examApply.getBirthDate())) {
                    int birthDays = DateUtil.getBirthDays(examApply.getBirthDate());
                    isAgeScope = (min <= birthDays && birthDays <= max);
                    if (isAgeScope) {
                        break;
                    }
                }
            }
        }
        // 开单时间
        RuleDto.NumScope reqDayScope = null;
        String reqDayScopeGrant = null;
        if (rule.getReqDayScope() != null) {
            reqDayScope = rule.getReqDayScope();
            reqDayScopeGrant = rule.getReqDayScope().getGrant();
        }
        boolean isReqDayScope = true;
        if (reqDayScope != null) {
            String min = (reqDayScope.getMin() == null) ? "0" : String.valueOf(reqDayScope.getMin());
            String max = (reqDayScope.getMax() == null) ? "" : String.valueOf(reqDayScope.getMax());
            if (StringUtils.isNotBlank(examApply.getReqDate())) {
                int reqDays = DateUtil.getIntervalDays(examApply.getReqDate(), date);
                isReqDayScope = (Integer.parseInt(min) <= reqDays);
                if (StringUtils.isNotBlank(max)) {
                    isReqDayScope = (Integer.parseInt(min) <= reqDays && reqDays <= Integer.parseInt(max));
                }
            }
        }
        // 项目个数
        RuleDto.NumScope itemCountScope = null;
        String itemCountScopeGrant = null;
        if (rule.getItemCountScope() != null) {
            itemCountScope = rule.getItemCountScope();
            itemCountScopeGrant = rule.getItemCountScope().getGrant();
        }
        boolean isItemCountScope = true;
        if (itemCountScope != null) {
            String min = (itemCountScope.getMin() == null) ? "0" : String.valueOf(itemCountScope.getMin());
            String max = (itemCountScope.getMax() == null) ? "" : String.valueOf(itemCountScope.getMax());
            int itemNum = examApply.getItems().size();
            isItemCountScope = (Integer.parseInt(min) <= itemNum);
            if (StringUtils.isNotBlank(max)) {
                isItemCountScope = (Integer.parseInt(min) <= itemNum && itemNum <= Integer.parseInt(max));
            }
        }

        // 孕周
        RuleDto.GestationalWeekScope gestationalWeekScope = null;
        String gestationalWeekScopeGrant = null;
        if (rule.getGestationalWeek() != null) {
            gestationalWeekScope = rule.getGestationalWeek();
            gestationalWeekScopeGrant = rule.getGestationalWeek().getGrant();
        }
        // 是否在孕期时间内
        boolean isGestationalWeekScope = true;
        if (gestationalWeekScope != null) {
            for (RuleDto.DayScope dayScopes : gestationalWeekScope.getDayScope()) {
                int min = dayScopes.getMin();
                int max = dayScopes.getMax();
                // 怀孕日期
                String pregnancyDate = StringUtils.isBlank(examApply.getPregnancyDate()) ? examApply.getLastMensesDate() : examApply.getPregnancyDate();
                if (StringUtils.isBlank(pregnancyDate)) {
                    isGestationalWeekScope = false;
                    break;
                }
                // 怀孕天数
                int pregnancyDays = DateUtil.getIntervalDays(pregnancyDate, date);
                isGestationalWeekScope = (min <= pregnancyDays && pregnancyDays <= max);
                if (isGestationalWeekScope) {
                    break;
                }
            }
        }

        // 申请单检查标记
        List<String> examflags = CommonUtil.examItemFlag(examApply.getFlags());

        // 检查规则构建申请单标记
        StringBuilder onlyDoExamBuf = new StringBuilder();
        StringBuilder noDoExamBuf = new StringBuilder();
        buildRuleExamFlag(rule, onlyDoExamBuf, noDoExamBuf);
        String onlyDoExam = StringUtils.isNotBlank(onlyDoExamBuf.toString()) ? onlyDoExamBuf.substring(1) : "";
        String noDoExam = StringUtils.isNotBlank(noDoExamBuf.toString()) ? noDoExamBuf.substring(1) : "";

        String[] onlyDoExamArr = onlyDoExam.split(",");
        String[] noDoExamArr = noDoExam.split(",");
        if (isExclude) {
            if (CollectionUtils.isNotEmpty(priorityOrder)) {
                String applyPriorityOrder = StringUtils.isBlank(examApply.getPriorityOrder()) ? "普通" : examApply.getPriorityOrder();
                if (priorityOrderGrant.contains("1")) {
                    if (priorityOrder.contains(applyPriorityOrder)) {
                        isStop = true;
                    }
                } else if (!priorityOrder.contains(applyPriorityOrder)) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(reqPhysician)) {
                if (reqPhysicianGrant.contains("1")) {
                    if (reqPhysician.contains(examApply.getReqPhysician())) {
                        isStop = true;
                    }
                } else if (!reqPhysician.contains(examApply.getReqPhysician())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(terminalTypes)) {
                if (terminalTypeGrant.contains("1")) {
                    if (terminalTypes.contains(examApply.getTerminalType())) {
                        isStop = true;
                    }
                } else if (!terminalTypes.contains(examApply.getTerminalType())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(ward)) {
                if (wardGrant.contains("1")) {
                    if (ward.contains(examApply.getReqWardCode())) {
                        isStop = true;
                    }
                } else if (!ward.contains(examApply.getReqWardCode())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(dept)) {
                if (deptGrant.contains("1")) {
                    if (dept.contains(examApply.getReqDept())) {
                        isStop = true;
                    }
                } else if (!dept.contains(examApply.getReqDept())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(nurseUnitList)) {
                if (nurseUnitGrant.contains("1")) {
                    if (nurseUnitList.contains(nurseUnit)) {
                        isStop = true;
                    }
                } else if (!nurseUnitList.contains(nurseUnit)) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(patientSource)) {
                if (patientSourceGrant.contains("1")) {
                    if (patientSource.contains(examApply.getPatientSource())) {
                        isStop = true;
                    }
                } else if (!patientSource.contains(examApply.getPatientSource())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(sex)) {
                if (sexGrant.contains("1")) {
                    if (sex.contains(examApply.getSex())) {
                        isStop = true;
                    }
                } else if (!sex.contains(examApply.getSex())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(transTool)) {
                if (transToolGrant.contains("1")) {
                    if (transTool.contains(examApply.getTransTool())) {
                        isStop = true;
                    }
                } else if (!transTool.contains(examApply.getTransTool())) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && CollectionUtils.isNotEmpty(diagnosKeyword) && StringUtils.isNotBlank(examApply.getClinDiag())) {
                boolean isContainsKey = true;
                if (diagnosKeywordGrant.contains("1")) {
                    for (String key : diagnosKeyword) {
                        if (examApply.getClinDiag().contains(key)) {
                            isContainsKey = false;
                            break;
                        }
                    }
                } else {
                    isContainsKey = false;
                    for (String key : diagnosKeyword) {
                        if (examApply.getClinDiag().contains(key)) {
                            isContainsKey = true;
                            break;
                        }
                    }
                }
                if (!isContainsKey) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop) {
                if (CollectionUtils.isNotEmpty(examflags) && StringUtils.isNotBlank(onlyDoExam)) {
                    for (String flags2 : onlyDoExamArr) {
                        if (examflags.contains(flags2)) {
                            isStop = true;
                            break;
                        }
                    }
                    isConfigure = true;
                }
                if (!isStop && StringUtils.isNotBlank(noDoExam)) {
                    for (String flags2 : noDoExamArr) {
                        if (!examflags.contains(flags2)) {
                            isStop = true;
                            break;
                        }
                    }
                    isConfigure = true;
                }
            }
            if (!isStop && CollectionUtils.isNotEmpty(dayScope)) {
                if (dayScopeGrant.contains("1")) {
                    if (isAgeScope) {
                        isStop = true;
                    }
                } else if (!isAgeScope) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && reqDayScope != null) {
                if (reqDayScopeGrant.contains("1")) {
                    if (isReqDayScope) {
                        isStop = true;
                    }
                } else if (!isReqDayScope) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && itemCountScope != null) {
                if (itemCountScopeGrant.contains("1")) {
                    if (isItemCountScope) {
                        isStop = true;
                    }
                } else if (!isItemCountScope) {
                    isStop = true;
                }
                isConfigure = true;
            }
            if (!isStop && gestationalWeekScope != null) {
                if (gestationalWeekScopeGrant.contains("1")) {
                    if (isGestationalWeekScope) {
                        isStop = true;
                    }
                } else if (!isGestationalWeekScope) {
                    isStop = true;
                }
                isConfigure = true;
            }
            return isStop || !isConfigure;
        }
        // 允许-优先级
        if (CollectionUtils.isNotEmpty(priorityOrder)) {
            String applyPriorityOrder = StringUtils.isBlank(examApply.getPriorityOrder()) ? "普通" : examApply.getPriorityOrder();
            if (priorityOrderGrant.contains("1")) {
                if (!priorityOrder.contains(applyPriorityOrder)) {
                    isStop = true;
                }
            } else if (priorityOrder.contains(applyPriorityOrder)) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(reqPhysician)) {
            if (reqPhysicianGrant.contains("1")) {
                if (!reqPhysician.contains(examApply.getReqPhysician())) {
                    isStop = true;
                }
            } else if (reqPhysician.contains(examApply.getReqPhysician())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(diagnosKeyword) && StringUtils.isNotBlank(examApply.getClinDiag())) {
            boolean isContainsKey = false;
            if (diagnosKeywordGrant.contains("1")) {
                for (String key : diagnosKeyword) {
                    if (examApply.getClinDiag().contains(key)) {
                        isContainsKey = true;
                        break;
                    }
                }
            } else {
                isContainsKey = true;
                for (String key : diagnosKeyword) {
                    if (examApply.getClinDiag().contains(key)) {
                        isContainsKey = false;
                        break;
                    }
                }
            }
            if (!isContainsKey) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(terminalTypes)) {
            if (terminalTypeGrant.contains("1")) {
                if (!terminalTypes.contains(examApply.getTerminalType())) {
                    isStop = true;
                }
            } else if (terminalTypes.contains(examApply.getTerminalType())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(ward)) {
            if (wardGrant.contains("1")) {
                if (!ward.contains(examApply.getReqWardCode())) {
                    isStop = true;
                }
            } else if (ward.contains(examApply.getReqWardCode())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(dept)) {
            if (deptGrant.contains("1")) {
                if (!dept.contains(examApply.getReqDept())) {
                    isStop = true;
                }
            } else if (dept.contains(examApply.getReqDept())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(nurseUnitList)) {
            if (nurseUnitGrant.contains("1")) {
                if (!nurseUnitList.contains(nurseUnit)) {
                    isStop = true;
                }
            } else if (nurseUnitList.contains(nurseUnit)) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(patientSource)) {
            if (patientSourceGrant.contains("1")) {
                if (!patientSource.contains(examApply.getPatientSource())) {
                    isStop = true;
                }
            } else if (patientSource.contains(examApply.getPatientSource())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(sex)) {
            if (sexGrant.contains("1")) {
                if (!sex.contains(examApply.getSex())) {
                    isStop = true;
                }
            } else if (sex.contains(examApply.getSex())) {
                isStop = true;
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(transTool)) {
            if (transToolGrant.contains("1")) {
                if (!transTool.contains(examApply.getTransTool())) {
                    isStop = true;
                }
            } else if (transTool.contains(examApply.getTransTool())) {
                isStop = true;
            }
        }
        if (!isStop) {
            if (CollectionUtils.isNotEmpty(examflags) && StringUtils.isNotBlank(noDoExam)) {
                for (String flags2 : noDoExamArr) {
                    if (examflags.contains(flags2)) {
                        isStop = true;
                        break;
                    }
                }
            }
            if (!isStop && StringUtils.isNotBlank(onlyDoExam)) {
                for (String flags2 : onlyDoExamArr) {
                    if (!examflags.contains(flags2)) {
                        isStop = true;
                        break;
                    }
                }
            }
        }
        if (!isStop && CollectionUtils.isNotEmpty(dayScope)) {
            if (dayScopeGrant.contains("1")) {
                if (!isAgeScope) {
                    isStop = true;
                }
            } else if (isAgeScope) {
                isStop = true;
            }
        }
        if (!isStop && reqDayScope != null) {
            if (reqDayScopeGrant.contains("1")) {
                if (!isReqDayScope) {
                    isStop = true;
                }
            } else if (isReqDayScope) {
                isStop = true;
            }
        }
        if (!isStop && itemCountScope != null) {
            if (itemCountScopeGrant.contains("1")) {
                if (!isItemCountScope) {
                    isStop = true;
                }
            } else if (isItemCountScope) {
                isStop = true;
            }
        }
        if (!isStop && gestationalWeekScope != null) {
            if (gestationalWeekScopeGrant.contains("1")) {
                if (!isGestationalWeekScope) {
                    isStop = true;
                }
            } else if (isGestationalWeekScope) {
                isStop = true;
            }
        }
        return isStop;
    }


    /**
     * 根据检查规则构建申请单标记
     *
     * @param rule
     * @param onlyDoExamBuf
     * @param noDoExamBuf
     */
    private void buildRuleExamFlag(RuleDto rule, StringBuilder onlyDoExamBuf, StringBuilder noDoExamBuf) {
        String clinicPath = rule.getClinicPath();
        if ("1".equals(clinicPath)) {
            onlyDoExamBuf.append(",7");
        } else if ("0".equals(clinicPath)) {
            noDoExamBuf.append(",7");
        }
        String bedSide = rule.getBedSide();
        if ("1".equals(bedSide)) {
            onlyDoExamBuf.append(",8");
        } else if ("0".equals(bedSide)) {
            noDoExamBuf.append(",8");
        }
        String vip = rule.getVip();
        if ("1".equals(vip)) {
            onlyDoExamBuf.append(",9");
        } else if ("0".equals(vip)) {
            noDoExamBuf.append(",9");
        }
        String criticallyIll = rule.getCriticallyIll();
        if ("1".equals(criticallyIll)) {
            onlyDoExamBuf.append(",11");
        } else if ("0".equals(criticallyIll)) {
            noDoExamBuf.append(",11");
        }
        String indolence = rule.getIndolence();
        if ("1".equals(indolence)) {
            onlyDoExamBuf.append(",12");
        } else if ("2".equals(indolence)) {
            noDoExamBuf.append(",12");
        }
        String infectious = rule.getInfectious();
        if ("1".equals(infectious)) {
            onlyDoExamBuf.append(",13");
        } else if ("0".equals(infectious)) {
            noDoExamBuf.append(",13");
        }
        String createDoc = rule.getCreateDoc();
        if ("1".equals(createDoc)) {
            onlyDoExamBuf.append(",14");
        } else if ("0".equals(createDoc)) {
            noDoExamBuf.append(",14");
        }
        String needToCalm = rule.getNeedToCalm();
        if ("1".equals(needToCalm)) {
            onlyDoExamBuf.append(",15");
        } else if ("0".equals(needToCalm)) {
            noDoExamBuf.append(",15");
        }
        String multiDrug = rule.getMultiDrug();
        if ("1".equals(multiDrug)) {
            onlyDoExamBuf.append(",16");
        } else if ("0".equals(multiDrug)) {
            noDoExamBuf.append(",16");
        }
    }

    /**
     * 数量判断
     *
     * @param examApply
     * @param dsa
     * @param date
     * @return true 数量充足 false 数量不足
     */
    public boolean quantityRuleJudge(ExamApplyDto examApply, DictScheduleApmDto dsa, String date) {
        List<String> apmCodeList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dsa.getApmCodes())) {
            apmCodeList.addAll(dsa.getApmCodes());
        } else {
            apmCodeList.add(dsa.getApmCode());
        }
        Map<String, List<String>> mapApmCodes = new HashMap<>();
        mapApmCodes.put(dsa.getApmCode(), apmCodeList);

        // 合并时段编码
        if (StringUtils.isNotBlank(dsa.getMergeApmCode())) {
            mapApmCodes.put(dsa.getMergeApmCode(), Arrays.asList(dsa.getMergeApmCode().split(",")));
        }
        List<String> regularIdList = new ArrayList<>();
        double minNum = 0.0;
        boolean isReduci = true;
        for (Map.Entry<String, List<String>> apmCodeEntry : mapApmCodes.entrySet()) {
            String apmCode = apmCodeEntry.getKey();
            List<String> apmCodes = apmCodeEntry.getValue();
            String key = String.format(ConstantsUtil.EhCacheKey.APM_REGULAR_INFO.getKey(), apmCode);

            // 数量规则
            List<DictScheduleApmRegular> quantityRules = EhCacheUtil.getValue(ConstantsUtil.EhCacheName.regularCache.name(), key);
            if (CollectionUtils.isEmpty(quantityRules)) {
                quantityRules = dictScheduleApmRegularServiceImpl.selectForMaxLimitList(apmCode, "3");
                if (CollectionUtils.isNotEmpty(quantityRules)) {
                    EhCacheUtil.putList(ConstantsUtil.EhCacheName.regularCache.name(), key, quantityRules);
                }
            }
            if (CollectionUtils.isNotEmpty(quantityRules)) {
                for (DictScheduleApmRegular dsar : quantityRules) {
                    // 时段预约规则
                    RuleDto rule = (RuleDto) EhCacheUtil.get(ConstantsUtil.EhCacheName.regularCache.name(), dsar.getRegularId());
                    if (rule == null) {
                        rule = dictScheduleApmRegularServiceImpl.getRuleDto(dsar.getRegularId());
                        if (rule != null) {
                            EhCacheUtil.put(ConstantsUtil.EhCacheName.regularCache.name(), dsar.getRegularId(), rule);
                        }
                    }
                    List<String> ruleitems = (rule != null && rule.getExamItem() != null) ? rule.getExamItem().getValue() : null;
                    if (StringUtils.isBlank(examApply.getIsGreenChannel())) {
                        if (rule != null) {
                            // 验证 开单时间 限制
                            if (rule.getReqDayScope() != null) {
                                RuleDto.NumScope reqDayScope = rule.getReqDayScope();
                                // 是否包含在 开单时间 内
                                boolean isReqDayScope = true;
                                // 包含
                                if ("1".equals(reqDayScope.getGrant())) {
                                    int min = (reqDayScope.getMin() == null) ? 0 : reqDayScope.getMin();
                                    int max = (reqDayScope.getMax() == null) ? -1 : reqDayScope.getMax();
                                    // 申请日期
                                    if (StringUtils.isNotBlank(examApply.getReqDate())) {
                                        int reqDays = DateUtil.getIntervalDays(examApply.getReqDate(), date);
                                        isReqDayScope = (min <= reqDays);
                                        if (max != -1) {
                                            isReqDayScope = (min <= reqDays && reqDays <= max);
                                        }
                                    }
                                }
                                if (!isReqDayScope) {
                                    continue;
                                }
                            }

                            // 病区限制
                            if (rule.getWard() != null) {
                                List<String> ward = rule.getWard().getValue();
                                if (!ward.contains(examApply.getReqWardCode())) {
                                    continue;
                                }
                            }
                            // 开单科室
                            if (rule.getDept() != null) {
                                List<String> dept = rule.getDept().getValue();
                                if (!dept.contains(examApply.getReqDept())) {
                                    continue;
                                }
                            }
                            // 病人来源
                            if (rule.getPatientSource() != null) {
                                List<String> patientSource = rule.getPatientSource().getValue();
                                if (!patientSource.contains(examApply.getPatientSource())) {
                                    continue;
                                }
                            }
                            // 优先级
                            if (rule.getPriorityOrder() != null) {
                                List<String> priorityOrder = rule.getPriorityOrder().getValue();
                                String applyPriorityOrder = StringUtils.isBlank(examApply.getPriorityOrder()) ? "普通" : examApply.getPriorityOrder();
                                if (!priorityOrder.contains(applyPriorityOrder)) {
                                    continue;
                                }
                            }
                            // 终端条件过滤
                            if (CollectionUtils.isNotEmpty(rule.getTerminalTypes())) {
                                List<String> terminalType = rule.getTerminalTypes();
                                if (!terminalType.contains(examApply.getTerminalType())) {
                                    continue;
                                }
                            }
                            // 患者属性
                            if (CollectionUtils.isNotEmpty(rule.getPatientAttributes())) {
                                List<String> examflags = CommonUtil.examItemFlag(examApply.getFlags());
                                List<String> patientAttributes = rule.getPatientAttributes();
                                List<String> pabList = new ArrayList<>();
                                for (String pab : patientAttributes) {
                                    if (ConstantsUtil.RegularAttribute.CLINIC_PATH.getKey().equals(pab)) {
                                        pabList.add("7");
                                    }
                                    if (ConstantsUtil.RegularAttribute.BED_SIDE.getKey().equals(pab)) {
                                        pabList.add("8");
                                    }
                                    if (ConstantsUtil.RegularAttribute.VIP.getKey().equals(pab)) {
                                        pabList.add("9");
                                    }
                                    if (ConstantsUtil.RegularAttribute.CRITICALLY_ILL.getKey().equals(pab)) {
                                        pabList.add("11");
                                    }
                                    if (ConstantsUtil.RegularAttribute.INDOLENCE.getKey().equals(pab)) {
                                        pabList.add("12");
                                    }
                                    if (ConstantsUtil.RegularAttribute.INFECTIOUS.getKey().equals(pab)) {
                                        pabList.add("13");
                                    }
                                    if (ConstantsUtil.RegularAttribute.CREATE_DOC.getKey().equals(pab)) {
                                        pabList.add("14");
                                    }
                                    if (ConstantsUtil.RegularAttribute.MULTI_DRUG.getKey().equals(pab)) {
                                        pabList.add("16");
                                    }
                                }
                                boolean isExamflag = false;
                                for (String flag : pabList) {
                                    if (examflags.contains(flag)) {
                                        isExamflag = true;
                                        break;
                                    }
                                }
                                if (!isExamflag) {
                                    continue;
                                }
                            }
                            if (rule.getAge() != null) {
                                List<RuleDto.DayScope> dayScope = rule.getAge().getDayScope();
                                boolean isAgeScope = true;
                                if (CollectionUtils.isNotEmpty(dayScope)) {
                                    for (RuleDto.DayScope days : dayScope) {
                                        int min = days.getMin();
                                        int max = days.getMax();
                                        int ageDays = DateUtil.getIntervalDays(examApply.getReqDate(), date);
                                        isAgeScope = (min <= ageDays && ageDays <= max);
                                        if (isAgeScope) {
                                            break;
                                        }
                                    }
                                }
                                if (!isAgeScope) {
                                    continue;
                                }
                            }

                            RuleDto.GestationalWeekScope gestationalWeekScope = null;
                            if (rule.getGestationalWeek() != null
                                    && CollectionUtils.isNotEmpty(rule.getGestationalWeek().getDayScope())) {
                                gestationalWeekScope = rule.getGestationalWeek();
                                boolean gestationalIsWeekScope = true;
                                for (RuleDto.DayScope dayScopes : gestationalWeekScope.getDayScope()) {
                                    int min = dayScopes.getMin();
                                    int max = dayScopes.getMax();
                                    String pregnancyDate = StringUtils.isBlank(examApply.getPregnancyDate()) ? examApply.getLastMensesDate() : examApply.getPregnancyDate();
                                    if (StringUtils.isBlank(pregnancyDate)) {
                                        gestationalIsWeekScope = false;
                                        break;
                                    }
                                    int pregnancyDays = DateUtil.getIntervalDays(pregnancyDate, date);
                                    gestationalIsWeekScope = (min <= pregnancyDays && pregnancyDays <= max);
                                    if (gestationalIsWeekScope) {
                                        break;
                                    }
                                }
                                if (!gestationalIsWeekScope) {
                                    continue;
                                }
                            }
                        }
                    }

                    // 开始数量验证
                    double needNum = 0.0;
                    List<String> itemCodes = new ArrayList<>();
                    List<String> itemCodeList = new ArrayList<>();
                    for (ExamApplyItemDto item : examApply.getItems()) {
                        if (ruleitems != null) {
                            if (!ruleitems.contains(item.getItemCode())) {
                                continue;
                            }
                            ++needNum;
                            itemCodes.add(item.getItemCode());
                            String itemCode = item.getItemCode().replace("-", "~");
                            itemCodeList.add(itemCode);
                        } else {
                            needNum = 1.0;
                        }
                    }
                    if (needNum == 0.0) {
                        continue;
                    }
                    double currentCount = commonServiceImpl.getExamScheduleApmRegular(apmCodes, dsar.getRegularId(), date, itemCodes);
                    double maxLimit = (dsar.getMaxLimit() == null) ? dsa.getMaxLimit() : dsar.getMaxLimit();
                    if (maxLimit <= 0.0) {
                        return false;
                    }
                    double residueNum = maxLimit - (currentCount + needNum);
                    if (residueNum < 0.0 && StringUtils.isBlank(examApply.getIsGreenChannel())) {
                        return false;
                    }
                    String st = apmCode + "=" + dsar.getRegularId() + "=" + currentCount + "=" + needNum + "=" + String.join(",", itemCodeList);
                    regularIdList.add(st);
                    double regularNum = maxLimit - currentCount;
                    if (minNum <= regularNum && minNum != 0.0) {
                        continue;
                    }
                    minNum = regularNum;
                }
            }
        }
        String remainSourceType = cacheServiceImpl.getConfigByName(ConstantsUtil.ConfigName.REMAIN_SOURCE_TYPE.getKey());
        if ("1".equals(remainSourceType)) {
            dsa.setRegularMinNum(minNum);
        }
        if (CollectionUtils.isNotEmpty(regularIdList)) {
            examApply.setRegularIdList(regularIdList);
        }
        return isReduci;
    }
}
